package com.ansion.basedb.database;

import android.database.sqlite.SQLiteDatabase;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;

import com.ansion.basedb.dao.helper.AppDatabaseHelper;
import com.ansion.basedb.dao.model.BaseModel;
import com.ansion.exception.ExceptionExtension;
import com.ansion.log.S;
import com.ansion.log.VLog;
import com.ansion.utils.BooleanCallback;

import java.util.ArrayList;
import java.util.List;


public class DataBaseHandler extends Handler {
	private AppDatabaseHelper appAppDatabase;
	private Handler uiHandler;

	public DataBaseHandler(AppDatabaseHelper apAppDatabase, Looper looper) {
		super(looper);
		this.appAppDatabase = apAppDatabase;
		uiHandler = new Handler(Looper.getMainLooper());
	}

	@Override
	public void handleMessage(Message msg) {
		if (msg != null) {
			try{
			switch (DatabaseOptionType.VALUEOF(msg.what)) {
				case OPTION_INSERT:
					insert(msg);
					break;
				case OPTION_UPDATE:
					update(msg);
					break;
				case OPTION_REPLACE:
					replace(msg);
					break;
				case OPTION_DELETE:
					delete(msg);
					break;
				case OPTION_EXEC_SQL:
					execSql(msg);
					break;
				default:
					break;
			}
			}catch(Throwable t){
				VLog.e("DBHandler", t);
			}
		}
	}

	private <T extends BaseModel> void insert(Message msg){
		if(msg.obj == null){
			return;
		}
		@SuppressWarnings("unchecked")
		DBMsgObject<T> msgObj = (DBMsgObject<T>)msg.obj;
        String tableName = !TextUtils.isEmpty(msgObj.tableName) ? msgObj.tableName : DatabaseTools.getTableName(msgObj.claz);
		if(!TextUtils.isEmpty(tableName) && msgObj.contentConditionList != null && msgObj.contentConditionList.size() > 0){
			SQLiteDatabase database = appAppDatabase
					.getWritableDatabase();
			if (database != null) {
				List<T> successModels = new ArrayList<T>();
				List<T> failModels = new ArrayList<T>();
				database.beginTransaction();
				try{
					for(DBMsgObject.ContentCondition<T> condition : msgObj.contentConditionList){
						if (condition != null && condition.contentValues != null) {
							long id = database.insert(tableName, null, condition.contentValues);
							if(id != -1){
								successModels.add(condition.model);
							}else{
								failModels.add(condition.model);
							}
						}
					}
					database.setTransactionSuccessful();// 设置事务处理成功，不设置会自动回滚不提交
				}
				catch (Throwable e){
					successModels.clear();
					VLog.e("DBHandler", e);
				}
				finally{
					database.endTransaction();
					postToMainLoop(msgObj,DatabaseOptionType.OPTION_INSERT ,successModels, failModels);//失败回调到主线程
				}
			}
		}
	}

	private <T extends BaseModel> void update(Message msg) {
		if(msg.obj == null){
			return;
		}
		@SuppressWarnings("unchecked")
		DBMsgObject<T> msgObj = (DBMsgObject<T>)msg.obj;
        String tableName = !TextUtils.isEmpty(msgObj.tableName) ? msgObj.tableName : DatabaseTools.getTableName(msgObj.claz);
		if(!TextUtils.isEmpty(tableName) && msgObj.contentConditionList != null && msgObj.contentConditionList.size() > 0){
			SQLiteDatabase database = appAppDatabase
					.getWritableDatabase();
			if (database != null) {
				List<T> successModels = new ArrayList<T>();
				List<T> failModels = new ArrayList<T>();
				database.beginTransaction();
				try{
					for(DBMsgObject.ContentCondition<T> condition : msgObj.contentConditionList){
						if (condition != null && condition.contentValues != null) {
							int count = database.update(tableName, condition.contentValues, condition.whereClause, condition.whereArgs);
							if(count > 0){
								successModels.add(condition.model);
							}else{
								failModels.add(condition.model);
							}
						}
					}
					database.setTransactionSuccessful();// 设置事务处理成功，不设置会自动回滚不提交
				}
				catch (Throwable e){
					successModels.clear();
					VLog.e("DBHandler", e);
				}
				finally{
					database.endTransaction();
					postToMainLoop(msgObj, DatabaseOptionType.OPTION_UPDATE, successModels, failModels);
				}
			}
		}
	}

	private <T extends BaseModel> void replace(Message msg){
		if(msg.obj == null){
			return;
		}
		@SuppressWarnings("unchecked")
		DBMsgObject<T> msgObj = (DBMsgObject<T>)msg.obj;
        String tableName = !TextUtils.isEmpty(msgObj.tableName) ? msgObj.tableName : DatabaseTools.getTableName(msgObj.claz);
		if(!TextUtils.isEmpty(tableName) && msgObj.contentConditionList != null && msgObj.contentConditionList.size() > 0){
			SQLiteDatabase database = appAppDatabase
					.getWritableDatabase();
			if (database != null) {
				List<T> successModels = new ArrayList<T>();
				List<T> failModels = new ArrayList<T>();
				database.beginTransaction();
				try{
					for(DBMsgObject.ContentCondition<T> condition : msgObj.contentConditionList){
						if (condition != null && condition.contentValues != null) {
							long id = database.replace(tableName, null, condition.contentValues);
							if(id != -1){
								successModels.add(condition.model);
							}else{
								failModels.add(condition.model);
							}
						}
					}
					database.setTransactionSuccessful();// 设置事务处理成功，不设置会自动回滚不提交
				}
				catch (Throwable e){
					successModels.clear();
					VLog.e("DBHandler", e);
				}
				finally{
					database.endTransaction();
					postToMainLoop(msgObj, DatabaseOptionType.OPTION_REPLACE, successModels, failModels);
				}
			}
		}
	}

	private <T extends BaseModel> void delete(Message msg){
		if(msg.obj == null){
			return;
		}
		@SuppressWarnings("unchecked")
		final DBMsgObject<T> msgObj = (DBMsgObject<T>)msg.obj;
        String tableName = !TextUtils.isEmpty(msgObj.tableName) ? msgObj.tableName : DatabaseTools.getTableName(msgObj.claz);
		if(!TextUtils.isEmpty(tableName) && msgObj.contentConditionList != null && msgObj.contentConditionList.size() > 0){
			SQLiteDatabase database = appAppDatabase
					.getWritableDatabase();
			if (database != null) {
				int rows = 0;
				database.beginTransaction();
				try{
					for(DBMsgObject.ContentCondition<T> condition : msgObj.contentConditionList){
						if (condition != null) {
							rows += database.delete(tableName, condition.whereClause, condition.whereArgs);
						}
					}
					database.setTransactionSuccessful();// 设置事务处理成功，不设置会自动回滚不提交
				}
				catch (Throwable e){
					VLog.e("DBHandler", e);
				}
				finally{
					database.endTransaction();
					if (msgObj.deleteListener != null) {
						final int tempRows = rows;
						if (msgObj.deleteListener.needUIThread()) {
							uiHandler.post(new Runnable() {

								@Override
								public void run() {
									// TODO Auto-generated method stub
									msgObj.deleteListener.onDeleteCallback(msgObj.claz, tempRows);
								}
							});
						} else {
							msgObj.deleteListener.onDeleteCallback(msgObj.claz, tempRows);
						}
					}
				}
			}
		}
	}

	private <T extends BaseModel> void postToMainLoop(final DBMsgObject<T> msgObj, final DatabaseOptionType type, final List<T> successModels, final List<T> failModels) {
		DBOperateAsyncListener listener = msgObj.listener;
		final Class<T> claz = msgObj.claz;
		if (listener != null) {
			if (listener.needUIThread()) {
				uiHandler.post(new Runnable() {

					@Override
					public void run() {
						// TODO Auto-generated method stub
						try {
							listener.onPostExecute(type, claz, successModels, failModels);
						} catch (Throwable t) {
							VLog.e("DBHandler", t);
						}
					}
				});
			} else {
				try {
					listener.onPostExecute(type, claz, successModels, failModels);
				} catch (Throwable t) {
					S.e(t);
				}
			}
		}
	}


	private void execSql(Message msg) {
		Object obj = msg.obj;
		if (obj instanceof DBSqlObject) {
			DBSqlObject dbSqlObject = (DBSqlObject) obj;
			SQLiteDatabase database = appAppDatabase
					.getWritableDatabase();
			if (database != null && !TextUtils.isEmpty(dbSqlObject.getSql())) {
				BooleanCallback callback = dbSqlObject.getCallback();
				try {
					Object[] args = dbSqlObject.getArgs();
					if (args != null) {
						database.execSQL(dbSqlObject.getSql(), args);
					} else {
						database.execSQL(dbSqlObject.getSql());
					}
					if (callback != null) {
						callback.onResult(true);
					}
				} catch (Throwable e) {
					if (callback != null) {
						callback.onResult(false);
					}
					ExceptionExtension.throwThrowable(e);
				}
			}
		}
	}
}
